package cube.data.util;

import cube.data.util.DataUtil;

/**
 * CRC算法类
 * 
 * @author abiao
 */
public abstract class CRC {

	/**
	 * CRC长度
	 */
	public static final int LEN = 2;

	/**
	 * crc table<br>
	 * poly 0x1021 : G(x)=x16+x12+x5+1
	 */
	private static char[] crc_tb = initTB16(0x1021);

	/**
	 * 16位CRC表
	 */
	private static char[] initTB16(int poly) {
		char[] table = new char[256];
		short msbit = (short) 0x8000;
		short t = msbit;

		for (int i = 1; i < table.length; i *= 2) {
			t = (short) ((t << 1) ^ ((t & msbit) != 0 ? poly : 0));
			for (int j = 0; j < i; j++) {
				table[i + j] = (char) (table[j] ^ t);
			}
		}
		return table;
	}

	/**
	 * 计算CRC校验码
	 */
	private static char calcCRC(byte[] data) {
		char crc = 0x0;
		for (int i = 0; i < data.length; i++) {
			crc = (char) ((crc << 8) ^ crc_tb[0xFF & (crc >> 8 ^ data[i])]);
		}
		return crc;
	}

	/**
	 * 检查CRC是否正确
	 */
	public static boolean checkCRC(byte[] data) {
		return (0 == calcCRC(data));
	}

	/**
	 * 获取数据CRC
	 */
	public static byte[] getCRC(byte[] data) {
		return DataUtil.char2bytes(CRC.calcCRC(data));
	}

	/**
	 * 为数据添加CRC
	 */
	public static byte[] addCRC(byte[] data) {
		return DataUtil.concat(data, getCRC(data));
	}

	/**
	 * 移除CRC数据
	 */
	public static byte[] rmvCRC(byte[] data) {
		return DataUtil.copy(data, 0, data.length - LEN);
	}
}
